import os
import time
import logging

import _judger
from django import forms
from django.core.serializers.json import DjangoJSONEncoder
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View

FILE_NAME_DIC = {1: "inactive", 2: "inactive", 3: "inactive", 4: "inactive",
                 5: "inactive"}

LANGUAGE_DIC = {1: "cpp", 2: "c", 3: "py"}

logger = logging.getLogger('django')


# logger.info('This is a log info')
# logger.debug('Debugging')
# logger.warning('Warning exists')
# logger.info('Finish')


class SubmitCode(forms.Form):
    """
    提交代码的表单
    """
    user_code = forms.CharField(label="代码", max_length=1024,
                                widget=forms.Textarea, required=True)
    user_input = forms.CharField(label="输入数据", max_length=1024, required=True)


class JsonResponseSelf(JsonResponse):
    """
    重写的JsonResponse
    在向客户端返回数据之前释放掉不用的文件名
    """

    def __init__(self, data, use_file_name, encoder=DjangoJSONEncoder,
                 safe=True, json_dumps_params=None, **kwargs):
        FILE_NAME_DIC[use_file_name] = 'inactive'
        super().__init__(data, encoder, safe, json_dumps_params, **kwargs)


class ProcessCodeView(View):
    """
    返回运行代码结果的视图类
    """
    # 用户代码和测试用例提交路径
    code_path = os.path.dirname(__file__) + "/user_codes"

    def get(self, request):
        """
        渲染出请求用户代码的表单页面
        """
        form = SubmitCode()
        return render(request, template_name="index.html",
                      context={'form': form})

    def post(self, request):
        """
        返回用户代码的运行结果
        """
        content = {}  # 返回的Json内容
        form_data = request.POST
        user_code = form_data.get('user_code')
        user_data_in = form_data.get('user_input')
        user_code_language = form_data.get("user_language")

        """检查接收到的参数"""
        # 代码存在
        if user_code is None:
            logger.info("code not exist")
            return JsonResponse({"msg": "没有输入代码"})
        # 输入输出存在
        if user_data_in is None:
            logger.info("data is not exist")
            return JsonResponse({"msg": "没有程序运行的输入数据"})
        # 语言类型存在
        if user_code_language is None:
            user_code_language = LANGUAGE_DIC[1]

        """选择出一个没有使用的文件名"""
        self.use_file_name = None
        for file_name, value in FILE_NAME_DIC.items():
            if value == 'inactive':
                self.use_file_name = file_name
                FILE_NAME_DIC[file_name] = 'active'
                break
        if self.use_file_name is None:
            logger.error("server is busy, cause have not file name can be use")
            return JsonResponse({"msg": "服务器繁忙"})
        logger.info("use_file_name is {}".format(self.use_file_name))

        """将用户提交的代码和输入数据写入文件中"""
        try:
            code_file = open(self.code_path + "/{}.cpp".format(
                self.use_file_name),
                             "w")
            code_file.write(user_code)

            input_file = open(
                self.code_path + "/{}.in".format(self.use_file_name),
                "w")
            input_file.write(user_data_in)
        except Exception as e:
            logger.error("file read and write faild")
            return JsonResponseSelf({"msg": "文件读写失败: {}".format(e)},
                                    use_file_name=self.use_file_name)
        finally:
            code_file.close()
            input_file.close()

        """运行代码"""
        ret = self.run_usercode()
        logger.info("program run result is {}".format(ret))

        """判断是否运行成功"""
        if ret == "error":
            content['status'] = "error"
            content['output'] = ""
            return JsonResponseSelf(content, use_file_name=self.use_file_name)
        else:
            with open(self.code_path + "/{}.out".format(self.use_file_name),
                      "r") as file:
                content['status'] = "success"
                content['output'] = file.read()
                return JsonResponseSelf(content,
                                        use_file_name=self.use_file_name)

    def run_usercode(self):
        """
        运行用户代码
        """
        if os.system(
                "g++ " + self.code_path + "/{}.cpp".format(
                    self.use_file_name) + " -o" + self.code_path + "/{}".format(
                    self.use_file_name)):
            return "error"
        else:
            return _judger.run(max_cpu_time=1000,
                               max_real_time=2000,
                               max_memory=128 * 1024 * 1024,
                               max_process_number=200,
                               max_output_size=10000,
                               max_stack=32 * 1024 * 1024,
                               # five args above can be _judger.UNLIMITED
                               exe_path=self.code_path + "/{}".format(
                                   self.use_file_name),
                               input_path=self.code_path + "/{}.in".format(
                                   self.use_file_name),
                               output_path=self.code_path + "/{}.out".format(
                                   self.use_file_name),
                               error_path=self.code_path + "/{}.out".format(
                                   self.use_file_name),
                               args=[],
                               # can be empty list
                               env=[],
                               log_path="judger.log",
                               # can be None
                               seccomp_rule_name="c_cpp",
                               uid=0,
                               gid=0)
